//======================================================================================
//  Apache License, Version 2.0
//  Notes:Use this command to anonymously check out the latest project source code:
//  Non-members may check out a read-only working copy anonymously over HTTP.
//  SVN checkout http://YHHLineCreateByGsdWsp.googlecode.com/svn/trunk/ 
//
//  Author:		Kevin Yang
//  Email:		Bigearrabbit@qq.com
//
//  DATE:		2013-4-7
//
//  File Name:	YHHLineCreateByGsdCore.cpp
//
//  Notes:
//
//======================================================================================
//Local Framework
#include "YHHLineCreateByGsdCore.h"
#include "YHHCatiaBaseDefine.h"

// ApplicationFrame Framework
#include "CATFrmEditor.h"                 // needed to retrieve the editor and then to highight objects

// ObjectModelerBase Framework
#include "CATIContainer.h"                // needed to create a GS (Geometrical Set)

// ObjectSpecsModeler Framework
#include "CATISpecObject.h"               // needed to manage feature
#include "CATIDescendants.h"              // needed to aggregate the newly created Line Create By GSD

// InteractiveInterfaces
#include "CATIBuildPath.h"                // needed to build a path element to highlight a feature

// MechanicalModeler Framework
#include "CATIMechanicalRootFactory.h"    // needed to create a GS 
#include "CATIGSMTool.h"                  // GSMTool and HybridBody features
#include "CATIBasicTool.h"                // To retrieve the current tool
#include "CATIMmiGeometricalSet.h"        // Only for GSMTool feature
#include "CATIMmiNonOrderedGeometricalSet.h"  // Only for GS feature

// MechanicalModelerUI Framework
#include "CATPrtUpdateCom.h"              // needed to update the feature according to the user's update settings
#include "CATMmrLinearBodyServices.h"     // To insert in ordered and linear body

// MecModInterfaces Framework
#include "CATIPrtPart.h"                  // needed to look for a GSM tool
#include "CATMfBRepDefs.h"                // needed to declare the modes of BRep feature creation

// Visualization Framework
#include "CATPathElement.h"               // needed to highlight objects
#include "CATHSO.h"                       // needed to highlight objects    
#include "CATIVisProperties.h"            // needed to change Line Create By GSD's graphical appearance
#include "CATVisPropertiesValues.h"
#include "iostream.h"					//need for CAA iostream.not c++  

//System framework
#include "CATGetEnvValue.h"               // To define the type of development
#include "CATBoolean.h"
#include "CATLib.h"

//GSMInterfaces  framework
#include "CATIGSMFactory.h"
#include "CATIGSMLinePtPt.h"

//GeometricObjects framework
#include "CATPoint.h"
#include "CATLine.h"

// This command is used by a CATCommandheader
#include "CATCreateExternalObject.h" 

CATImplementClass( YHHLineCreateByGsdCore,
                   Implementation, 
                   CATBaseUnknown,
                   CATNull );
 
//-----------------------------------------------------------------------------
YHHLineCreateByGsdCore::YHHLineCreateByGsdCore()
: CATBaseUnknown()
, m_CurrentElt(NULL_var)
, m_MyFeature(NULL_var)
, m_pParamGsd(NULL)
{
}
//-----------------------------------------------------------------------------
YHHLineCreateByGsdCore::~YHHLineCreateByGsdCore()
{
}
//-----------------------------------------------------------------------------
YHHLineCreateByGsdCore::YHHLineCreateByGsdCore(YHHLineCreateByGsdCore& original):
   CATBaseUnknown(original)
{
}
//-----------------------------------------------------------------------------
YHHLineCreateByGsdCore& YHHLineCreateByGsdCore::operator=(YHHLineCreateByGsdCore& original)
{
   CATBaseUnknown::operator=(original);
   return *this;
}
//-----------------------------------------------------------------------------
HRESULT YHHLineCreateByGsdCore::Create()
{
	cout <<" YHHLineCreateByGsdCore::Create" << endl;
	m_MyFeature = NULL_var;//clear first
	if (NULL == m_pParamGsd)return E_INVALIDARG;//param pointer check
	if (NULL == m_pEditor)return E_INVALIDARG;//editor pointer check

	//check input:
	if (!m_pParamGsd->StartPoint || !m_pParamGsd->LineDirection)
	{
		return E_INVALIDARG;//input not enouph
	}
	HRESULT rc = E_FAIL ;

	//
	// 1- Looking for a body to create the Line Create By GSD
	//    
	// 

	// CATIGSMTool is implemented by the HybridBody and GSMTool StartUp
	// it is a valid pointer to handle the body which will contain the new
	// Line Create By GSD
	//
	CATIGSMTool * piGSMTool = NULL ;

	char * pLineCreateByGsdOGS = NULL ;
	CATLibStatus result = ::CATGetEnvValue("YHHLineCreateByGsdOGS",&pLineCreateByGsdOGS);  
	if ( (CATLibError == result) || ( NULL == pLineCreateByGsdOGS) )
	{
		char * pLineCreateByGsdNoHybridBody = NULL ;
		result = ::CATGetEnvValue("YHHLineCreateByGsdNoHybridBody",&pLineCreateByGsdNoHybridBody); 
		if ( (CATLibError == result) || ( NULL == pLineCreateByGsdNoHybridBody) )
		{
			// Looking for or creating only a Geometrical Set
			// The result cannot be an ordered geometrical set or an hybrid body
			// 
			rc = LookingForGeomSet(&piGSMTool);
		}else
		{
			free (pLineCreateByGsdNoHybridBody) ;
			pLineCreateByGsdNoHybridBody = NULL ;

			// Looking for an OGS or a GS, or creating a Geometrical Set
			// The result cannot be an hybrid body
			//
			rc = LookingForGeomSetOrOrderedGeomSet(&piGSMTool);   
		}
	}else
	{
		free (pLineCreateByGsdOGS) ;
		pLineCreateByGsdOGS = NULL ;

		// Looking for any type of mechanical bodies, or creating a Geometrical Set
		// The result cannot be a former solid body
		//
		rc = LookingForAnyTypeOfBody(&piGSMTool);       
	}

	//
	// 2- Creating the Line Create By GSD
	// 
	CATISpecObject * piSpecOnLineCreateByGsd = NULL ;

	if ( SUCCEEDED(rc) && ( NULL != piGSMTool) )
	{   
		// 
		// 2.1 Uses YHHILineCreateByGsdFactory implemented by CATPrtCont
		// 
		CATISpecObject_var piSpecObjOnTool = piGSMTool ;

		if (!piSpecObjOnTool) //check pointer
		{
			rc = E_FAIL ;//find error 
			goto endOfStep2;//finish step 2
		}

		// 2.2  GetFeatContainer for a mechanical feature
		// is CATPrtCont, the specification container
		CATIContainer_var spContainer = piSpecObjOnTool->GetFeatContainer();  

		if (!spContainer) //check pointer
		{
			rc = E_FAIL ;//find error 
			goto endOfStep2;//finish step 2
		}

		//2.3 get gsm fatory:
		// Instantiates the wireframe factory
		CATIGSMFactory * piGSMFactOnPrtCont = NULL ;
		rc = spContainer->QueryInterface(IID_CATIGSMFactory,(void**)& piGSMFactOnPrtCont);
		if ( FAILED(rc) )
		{
			cout << "ERROR in instantiating the wireframe factory" << endl;
			goto endOfStep2;//finish step 2
		}

		// 2.4  creates the Line Create By GSD

		//(a)get coordinate from startpoint
		CATPoint_var sp1= m_pParamGsd->StartPoint;
		if (!sp1) 
		{
			rc = E_FAIL ;//find error 
			goto endOfStep2;//finish step 2
		}
		
		//(b)get point
		CATMathPoint Pt1 = sp1->GetMathPoint();

		//(c)get direction
		CATLine_var spLine= m_pParamGsd->LineDirection;
		if (!spLine) 
		{
			rc = E_FAIL ;//find error 
			goto endOfStep2;//finish step 2
		}
		//(d)get direction
		CATMathDirection dir = spLine->GetDirection();

		//(e)calculate length
		double length = 1000 * m_pParamGsd->LengthValue;//to mm
		if (m_pParamGsd->LengthSign<0) length *= -1;//invert
		CATMathPoint Pt2 = Pt1 +  length *dir;//calulate end point

		//(f)create end point
		double coord[3];//coord
		Pt2.GetCoord(coord);//get coord
		CATIGSMPoint_var spEndPoint = piGSMFactOnPrtCont->CreatePoint(coord);
		if (!spEndPoint) 
		{
			rc = E_FAIL ;//find error 
			goto endOfStep2;//finish step 2
		}
		//(g)create line
		m_MyFeature = piGSMFactOnPrtCont->
			CreateLine(m_pParamGsd->StartPoint ,spEndPoint);

		piSpecOnLineCreateByGsd = m_MyFeature;//set to the piSpecOnLineCreateByGsd

		//update
		if (NULL_var != m_MyFeature)m_MyFeature->Update();//update
	}
endOfStep2:

	//
	// 3- Aggregating the newly Line Create By GSD in the Geometrical Set
	// 
	if ( SUCCEEDED(rc) && (NULL != piGSMTool) && (NULL !=piSpecOnLineCreateByGsd) )
	{
		CATIDescendants * pIDescendantsOnGSMTool = NULL ;
		rc = piGSMTool->QueryInterface(IID_CATIDescendants, (void**) & pIDescendantsOnGSMTool);
		if ( SUCCEEDED(rc) )
		{
			// Checks the type of the GSMTool
			// 
			int TypeOrderedBody = -1 ;
			piGSMTool->GetType(TypeOrderedBody);

			if ( 1 == TypeOrderedBody )
			{  // OGS/HB : the CC is set after the current feature or at the end
				//       of the set, if the current feature is the set itself
				//
				cout <<" Ordered and linear body " << endl;
				int pos = 0 ;
				if ( NULL_var != m_CurrentElt)
				{
					pos = pIDescendantsOnGSMTool->GetPosition(m_CurrentElt);                   
				}

				if ( 0 == pos )
				{
					// The current feature is the GSMTool itself
					// the CC is appended at the end
					pIDescendantsOnGSMTool->Append(piSpecOnLineCreateByGsd);
				}else
				{
					// the current feature is inside the GSMTool
					// the CC is appended just below it (which can be at the end)
					pIDescendantsOnGSMTool->AddChild(piSpecOnLineCreateByGsd,pos+1);
				}
			}else
			{  // GS : the CC is set at the end of the set
				cout <<" GS case " << endl;
				pIDescendantsOnGSMTool->Append(piSpecOnLineCreateByGsd);
			}
			YHHRelease(pIDescendantsOnGSMTool);//release
		}
	}
endOfStep3:

	YHHReleaseIf(piGSMTool);//release
	YHHReleaseIf(piSpecOnLineCreateByGsd);//release

	return rc ;
}
//-----------------------------------------------------------------------------
HRESULT YHHLineCreateByGsdCore::CreateTool(CATIPrtPart * pIPrtPart, CATIGSMTool ** pIGsmTool)
{
	if ( ( pIGsmTool == NULL) || ( NULL == pIPrtPart ) )
	{
		return E_FAIL ;
	}

	*pIGsmTool  = NULL ;

	HRESULT rc = E_FAIL ;

	CATISpecObject * pISpecOnPart = NULL ;
	rc = pIPrtPart->QueryInterface(IID_CATISpecObject,(void**) &pISpecOnPart) ;
	if ( SUCCEEDED(rc) )
	{

		// GetFeatContainer for a mechanical feature
		// is CATPrtCont, the specification container
		CATIContainer_var spContainer = pISpecOnPart->GetFeatContainer();  
		if ( NULL_var != spContainer )
		{
			// 
			CATIMechanicalRootFactory * pMechanicalRootFactory = NULL;
			rc = spContainer->QueryInterface( IID_CATIMechanicalRootFactory , 
				( void**)& pMechanicalRootFactory );
			if ( SUCCEEDED(rc) )
			{
				// creates a new GS aggregated by the Part feature
				CATISpecObject_var spiSpecOnGSMTool;
				rc = pMechanicalRootFactory->CreateGeometricalSet( "" , pIPrtPart,spiSpecOnGSMTool);

				pMechanicalRootFactory->Release();
				pMechanicalRootFactory = NULL ;

				if ( NULL_var != spiSpecOnGSMTool )
				{
					spiSpecOnGSMTool->QueryInterface(IID_CATIGSMTool, (void**) &(*pIGsmTool));
				}
			}
		}

		pISpecOnPart->Release();
		pISpecOnPart = NULL ;

	}

	return rc ;
}
//---------------------------------------------------------
HRESULT YHHLineCreateByGsdCore::ExtractParams(YHHILineCreateByGsd *ipInstance,YHHLineCreateByGsdParam & oParam)
{
	// Reads the inputs of the Line Command.
	HRESULT rc = S_OK;
	//rc = ipInstance->GetParams(oParam) ;
	//oParam.SelfSpecObject = (YHHILineCreateByGsd_var)ipInstance;
	return rc;//return
}
//-----------------------------------------------------------------------------
HRESULT YHHLineCreateByGsdCore::LookingForAnyTypeOfBody(CATIGSMTool ** piGsmtool)
{
	if ( (NULL == piGsmtool) || (NULL ==m_pEditor) ) return E_FAIL ;

	HRESULT rc= E_FAIL ;

	*piGsmtool = NULL ;

	CATIPrtPart * pIPrtPart = NULL ;
	CATPathElement PathAct = m_pEditor->GetUIActiveObject();

	rc = PathAct.Search(IID_CATIPrtPart,(void**)&pIPrtPart)  ;

	if ( SUCCEEDED(rc) && ( NULL!=pIPrtPart) )
	{
		CATBoolean ToolToCreate = TRUE ;  

		CATIBasicTool_var CurrentTool ;
		CurrentTool = pIPrtPart->GetCurrentTool() ;

		if ( NULL_var != CurrentTool )
		{
			// is it a GSMTool or an hybrid body ?
			CATIGSMTool * pIGSMToolOnCurrentTool = NULL ;
			rc = CurrentTool->QueryInterface(IID_CATIGSMTool, (void**) &pIGSMToolOnCurrentTool);
			if ( SUCCEEDED(rc) )
			{
				// Ok we have found a valid body
				ToolToCreate = FALSE ;

				*piGsmtool = pIGSMToolOnCurrentTool ;
			}
		}

		if ( TRUE == ToolToCreate )
		{
			rc = CreateTool(pIPrtPart,piGsmtool);
		}

	}
	YHHReleaseIf(pIPrtPart);//release

	return rc ;
}
//---------------------------------------------------------
HRESULT YHHLineCreateByGsdCore::LookingForGeomSet(CATIGSMTool ** piGsmtool)
{
	if ( (NULL == piGsmtool) || (NULL ==m_pEditor) ) return E_FAIL ;

	HRESULT rc= E_FAIL ;

	*piGsmtool = NULL ;

	// Retrieves the Part feature which holds the current tool
	// 
	CATIPrtPart * pIPrtPart = NULL ;
	CATPathElement PathAct = m_pEditor->GetUIActiveObject();
	rc = PathAct.Search(IID_CATIPrtPart,(void**)&pIPrtPart) ;

	if ( SUCCEEDED(rc) && ( NULL!=pIPrtPart) )
	{
		CATBoolean ToolToCreate = TRUE ;

		CATIBasicTool_var CurrentTool ;
		CurrentTool = pIPrtPart->GetCurrentTool() ;

		if ( NULL_var != CurrentTool )
		{
			// is it a GS ?
			CATIMmiNonOrderedGeometricalSet * pIGSOnCurrentTool = NULL ;
			rc = CurrentTool->QueryInterface(IID_CATIMmiNonOrderedGeometricalSet, 
				(void**) &pIGSOnCurrentTool);
			if ( SUCCEEDED(rc) )
			{
				// Ok we have found a valid geometrical set
				ToolToCreate = FALSE ;

				rc = pIGSOnCurrentTool->QueryInterface(IID_CATIGSMTool, (void**) piGsmtool);
				YHHRelease(pIGSOnCurrentTool);//release
			}
		}

		if ( TRUE == ToolToCreate )
		{
			rc = CreateTool(pIPrtPart,piGsmtool);
		}
	}
	YHHReleaseIf(pIPrtPart);//release

	return rc ;
}
//-----------------------------------------------------------------------------
HRESULT YHHLineCreateByGsdCore::LookingForGeomSetOrOrderedGeomSet(CATIGSMTool ** piGsmtool)
{
	if ( (NULL == piGsmtool) || (NULL ==m_pEditor) ) return E_FAIL ;

	HRESULT rc= E_FAIL ;

	*piGsmtool = NULL ;

	CATIPrtPart * pIPrtPart = NULL ;
	CATPathElement PathAct = m_pEditor->GetUIActiveObject();

	rc = PathAct.Search(IID_CATIPrtPart,(void**)&pIPrtPart)  ;

	if ( SUCCEEDED(rc) && ( NULL!=pIPrtPart) )
	{
		CATBoolean ToolToCreate = TRUE ;  

		CATIBasicTool_var CurrentTool ;
		CurrentTool = pIPrtPart->GetCurrentTool() ;

		if ( NULL_var != CurrentTool )
		{
			// is it a GSMTool ?
			CATIMmiGeometricalSet * pIGSMToolOnCurrentTool = NULL ;
			rc = CurrentTool->QueryInterface(IID_CATIMmiGeometricalSet, (void**) &pIGSMToolOnCurrentTool);
			if ( SUCCEEDED(rc) )
			{
				// Ok we have found a valid geometrical set ( ordered or not )
				ToolToCreate = FALSE ;

				rc = pIGSMToolOnCurrentTool->QueryInterface(IID_CATIGSMTool, (void**) piGsmtool);
				YHHRelease(pIGSMToolOnCurrentTool);//release
			}
		}

		if ( (TRUE == ToolToCreate) )
		{
			rc = CreateTool(pIPrtPart,piGsmtool);
		}

	}
	YHHReleaseIf(pIPrtPart);//release
	return rc ;
}
//---------------------------------------------------------
